package com.asp.aspchain.tsttransaction.service.impl;

import com.alibaba.fastjson.JSON;
import com.asp.aspchain.core.dao.AppBaseMapper;
import com.asp.aspchain.core.dao.MgrAccountMapper;
import com.asp.aspchain.core.dao.TocAccountMapper;
import com.asp.aspchain.core.dao.TransactionMapper;
import com.asp.aspchain.core.ethereum.EthService;
import com.asp.aspchain.core.model.AppBaseModel;
import com.asp.aspchain.core.model.MgrAccountModel;
import com.asp.aspchain.core.model.TocAccountModel;
import com.asp.aspchain.core.model.TransactionModel;
import com.asp.aspchain.core.util.AjaxResult;
import com.asp.aspchain.core.util.DateUtil;
import com.asp.aspchain.tsttransaction.request.TransactionCommitReq;
import com.asp.aspchain.tsttransaction.service.EoaCommitService;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.web3j.protocol.core.methods.request.Transaction;

import java.io.IOException;
import java.math.BigInteger;
import java.security.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author zhongzifeng
 */
@Service
public class EoaCommitServiceImpl implements EoaCommitService {
	private final static Logger logger = Logger.getLogger(EoaCommitServiceImpl.class);

	@Value("${tst.accountkey}")
	private String accountKey;

    @Autowired
	private EthService ethService;

	@Autowired
	private MgrAccountMapper mgrAccountMapper;

	@Autowired
	private TocAccountMapper tocAccountMapper;

	@Autowired
	private AppBaseMapper appBaseMapper;

	@Autowired
    private TransactionMapper transactionMapper;


	/**
	 * 账户充值
	 * @param json transaction commit param
	 * @return
	 */
	@Override
	public AjaxResult eoaCommit(String json){
        AjaxResult result = new AjaxResult();
        try {
            // 转换参数至实体
            TransactionCommitReq req = JSON.parseObject(json, TransactionCommitReq.class);
            MgrAccountModel selectMgrAccount = new MgrAccountModel();
            // 校验充值账户是否属于指定appmark
            selectMgrAccount.setAccoutkey(accountKey);
            MgrAccountModel mgrAccountModel = mgrAccountMapper.selectOne(selectMgrAccount);
            String appmark = req.getAppmark();
            AppBaseModel selectAppBase = new AppBaseModel();
            selectAppBase.setAppmark(appmark);
            AppBaseModel appBaseModel = appBaseMapper.selectOne(selectAppBase);
            if(appBaseModel==null || "".equals(appBaseModel.getAppid())){
                logger.error("EOA-TST-充值失败，无appmark相关配置");
                result.setStatus("1");
                result.setMessage("充值失败，无appmark相关配置");
                return result;
            }
            String toAccount = req.getAccountid();
            TocAccountModel tocAccountModel = tocAccountMapper.selectById(toAccount);
            if(tocAccountModel==null ||
                    !appBaseModel.getAppid().equals(tocAccountModel.getAppid())){
                logger.error("EOA-TST-充值失败，非appid："+appmark+" 关联用户");
                result.setStatus("1");
                result.setMessage("充值失败，非appid："+appmark+" 关联用户");
                return result;
            }
            // 校验orderid是否已经使用
            String orderId = req.getOrderid();
            Wrapper<TransactionModel> wrapper = new EntityWrapper<TransactionModel>();
            wrapper.eq("orderid",orderId);
            int orderIdCount = transactionMapper.selectCount(wrapper);
            if(orderIdCount>0){
                logger.error("EOA-TST-充值失败，orderid："+orderId+" 已存在");
                result.setStatus("1");
                result.setMessage("充值失败，orderid："+orderId+" 已存在");
                return result;
            }

            BigInteger value = req.getTokenvalue();
            String password = req.getPassword();
            String from = mgrAccountModel.getAccountid();
            Transaction createEtherTransaction = new Transaction(from, null, null, null, toAccount, value,  null);

			String transactionHash = ethService.sendTransaction(createEtherTransaction,password);
			logger.info("EOA-TST-区块链生成的交易号(transactionHash)："+transactionHash);
			// 请求异常情况处理
			if(StringUtils.isEmpty(transactionHash)){
                logger.error("EOA-TST-充值失败，TransactionHash 为空");
                result.setStatus("1");
                result.setMessage("充值失败，TransactionHash 为空");
                return result;
            }

            // 成功发起交易写入交易记录表
            logger.info("EOA-TST-写入交易记录");
            TransactionModel transactionModel = new TransactionModel();
            transactionModel.setTradeid("ZL" + System.currentTimeMillis());
            transactionModel.setOrdertime(DateUtil.parseTime(req.getOrdertime()));
            transactionModel.setOrderid(orderId);
			transactionModel.setAppid(appBaseModel.getAppid()+"appid");
			transactionModel.setTradetype("0001");
			transactionModel.setCreatetime(new Date());
			transactionModel.setUpdatetime(new Date());
			transactionModel.setFromaaccountid(from);
			transactionModel.setFromtype("00");
			transactionModel.setToaaccountid(toAccount);
			transactionModel.setTotype("00");
			transactionModel.setTokentype("tst");
			transactionModel.setTokenvalue(value);
			transactionModel.setTransactionid(transactionHash);
			transactionModel.setStatus("00");
			transactionModel.setTranstime(new Date());
            transactionMapper.insert(transactionModel);

            result.setStatus("0");
            result.setMessage("交易提交成功");
            Map<String,Object> context = new HashMap<String,Object>(3);
            context.put("tradeid",transactionModel.getTradeid());
            context.put("transactionid",transactionModel.getTransactionid());
            context.put("status",transactionModel.getStatus());
            result.setContext(context);
		} catch (IOException e) {
			e.printStackTrace();
            logger.error("EOA-TST-充值失败，连接以太坊失败");
            result.setStatus("1");
            result.setMessage("充值失败，连接以太坊失败");
            return result;
		}
		return result;
	}



}
